﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Configuration;
using Nollie.UnitTests;
using System.Threading.Tasks;
using Nollie.CacheTypes.Mixed;
using Nollie.CacheTypes;
using Nollie.CacheTypes.Database;

namespace Nollie.IntegrationTests
{
	[TestClass]
	public class MixedCacheTests
	{
		private static IMixedCache _cache;

		[ClassInitialize]
		public static void Initialize(TestContext context)
		{
			var configuration = new CacheConfiguration();
			configuration.ConnectionString = ConfigurationManager.ConnectionStrings["Nollie"].ConnectionString;

			_cache = CacheFactory.GetMixedCache("Mixed", configuration);

			_cache.ClearAllPartitions();
		}
		private IPartition CreateMixedPartition()
		{
			return _cache.GetMixedPartition(Guid.NewGuid().ToString(), 100);
		}
		private IPartition CreateDbPartition()
		{
			return _cache.GetDbPartition(Guid.NewGuid().ToString());
		}
		private IPartition CreateMemPartition()
		{
			return _cache.GetMemPartition(Guid.NewGuid().ToString(), 100);
		}

		[TestMethod]
		public void Clear_should_delete_all_items_within_partition()
		{
			var partition = CreateMixedPartition();

			for (int i = 0; i < 10; i++)
			{
				var item = TestDataHelper.GetValidCacheItem(i.ToString());

				partition.Add(item);
			}

			Assert.AreEqual(10, partition.Count());

			partition.Clear();

			Assert.AreEqual(0, partition.Count());
		}
		[TestMethod]
		public void Add_item_should_be_added_to_database()
		{
			var partition = CreateMixedPartition();

			var item = TestDataHelper.GetValidCacheItem("1");
			partition.Add(item);

			Assert.AreEqual((item.Value as Customer).Name, partition.Get<Customer>("1").Name);
		}
		[TestMethod]
		public void Get_item_is_returned_if_not_expired()
		{
			var partition = CreateMixedPartition();

			var item = TestDataHelper.GetValidCacheItem("1");
			partition.Add(item);

			Assert.AreEqual((item.Value as Customer).Name, partition.Get<Customer>("1").Name);
		}
		[TestMethod]
		public void Get_null_is_returned_if_key_is_not_found()
		{
			var partition = CreateMixedPartition();

			Assert.AreEqual(null, partition.Get<Customer>("2"));
		}
		[TestMethod]
		public void Delete_item_from_cache()
		{
			var partition = CreateMixedPartition();

			var item = TestDataHelper.GetValidCacheItem("1");
			partition.Add(item);

			Assert.AreEqual(1, partition.Count());

			partition.RemoveByCacheKey("1");

			Assert.AreEqual(0, partition.Count());
		}
		[TestMethod]
		public void Delete_item_from_cache_by_dependency_key()
		{
			var partition = CreateMixedPartition();

			var item = TestDataHelper.GetValidCacheItem("1");
			item.Tags.Add("123");
			partition.Add(item);

			Assert.AreEqual(1, partition.Count());

			partition.RemoveByTag("123");

			Assert.AreEqual(0, partition.Count());
		}
		[TestMethod]
		public void Add_items_in_parallel()
		{
			var partition = CreateMixedPartition();

			Parallel.For(0, 100, i =>
				{
					var item = TestDataHelper.GetValidCacheItem(i.ToString());
					partition.Add(item);

					Assert.AreEqual((item.Value as Customer).Name, partition.Get<Customer>(i.ToString()).Name);
				}
			);
		}
		[TestMethod]
		public void CacheRemoveByTag_should_remove_item_with_tag_from_all_partitions()
		{
			var item = TestDataHelper.GetValidCacheItem("1");
			item.Tags.Add("tag:1");

			var partition1 = CreateMixedPartition();
			partition1.Add(item);

			Assert.AreEqual(1, partition1.Count());

			var partition2 = CreateMixedPartition();
			partition1.Add(item);

			Assert.AreEqual(1, partition1.Count());

			_cache.RemoveByTag("tag:1");

			Assert.AreEqual(0, partition1.Count());
			Assert.AreEqual(0, partition2.Count());
		}
		[TestMethod]
		public void GetPartition_should_return_existing_partition_if_key_already_exists()
		{
			var partitionName = Guid.NewGuid().ToString();

			var partition1 = _cache.GetMemPartition(partitionName, 100);

			var partition2 = _cache.GetMemPartition(partitionName, 100);

			Assert.AreEqual(partition1, partition2);
		}
		[ClassCleanup]
		public static void Finished()
		{
			_cache.ClearAllPartitions();
		}
	}
}
